package com.wish.blessingroad.service.impl;

import com.google.gson.Gson;
import com.thoughtworks.xstream.XStream;
import com.wish.blessingroad.common.Constant;
import com.wish.blessingroad.common.RedisKey;
import com.wish.blessingroad.config.ServiceException;
import com.wish.blessingroad.config.WeChatConfig;
import com.wish.blessingroad.entity.Orders;
import com.wish.blessingroad.entity.User;
import com.wish.blessingroad.entity.weChat.*;
import com.wish.blessingroad.service.IOrdersService;
import com.wish.blessingroad.service.IUserService;
import com.wish.blessingroad.util.*;
import com.wish.blessingroad.util.WeChat.PayUtil;
import com.wish.blessingroad.util.WeChat.Signature;
import com.wish.blessingroad.util.WeChat.WeChatUtil;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.params.SetParams;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author dhc
 * @since 2019-02-18
 */
@Service
public class WeChatServiceImpl {
    private static final Logger LOG = LoggerFactory.getLogger(WeChatServiceImpl.class);
    @Autowired
    private IUserService userServiceImpl;
    @Autowired
    private WeChatConfig weChatConfig;
    @Autowired
    private IOrdersService ordersServiceImpl;
    @Autowired
    private JedisUtil jedisUtil;
    //交易类型
    private final String trade_type = "JSAPI";
    //统一下单API接口链接
    private final String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    /**
     * 微信code换openid返回userid
     */
    public String wxlogin(String code) {
        String openid =
                WeChatUtil.getToken(code, weChatConfig.getAppIdx(), weChatConfig.getAppSecretx());
        User user = userServiceImpl.getByOpenId(openid);
        //没有则保存一个新的用户信息，并保存两缓存
        if (user == null) {
            user.setOpenid(openid);
            userServiceImpl.addUser(user);
        }
        jedisUtil.setex(RedisKey.getUserId(openid), Constant.TO_DAY_TIME, new Gson().toJson(user));
        jedisUtil.setex(RedisKey.getUserId(user.getId() + ""), Constant.TO_DAY_TIME,
                new Gson().toJson(user));
        //返回成功
        return user.getId() + "";
    }

    /**
     * 小程序邀请，微信code换openid返回userid
     */
    public String wxloginInvite(String code, String userIdTo) {
        String openid =
                WeChatUtil.getToken(code, weChatConfig.getAppIdx(), weChatConfig.getAppSecretx());
        User user = userServiceImpl.getByOpenId(openid);
        //没有则保存一个新的用户信息，并保存两缓存
        if (user == null) {
            user.setOpenid(openid);
            user.setRecommendId(Integer.valueOf(userIdTo));
            userServiceImpl.addUser(user);
        }
        jedisUtil.setex(RedisKey.getUserId(openid), Constant.TO_DAY_TIME, new Gson().toJson(user));
        jedisUtil.setex(RedisKey.getUserId(user.getId() + ""), Constant.TO_DAY_TIME,
                new Gson().toJson(user));
        //返回成功
        return user.getId() + "";
    }

    /**
     * * 微信支付
     *
     * @param userId     用户id
     * @param userName   用户名
     * @param avatarUrl  头像
     * @param blessingId 祝福表id
     * @param money      钱 单位 ：分
     * @param request
     * @return
     */
    public Map payment(String userId, String userName, String avatarUrl, String blessingId,
            String money,
            HttpServletRequest request) {
        if (Integer.parseInt(money) <= 0) {
            LOG.error("金额必须大于0 userId={},money={},blessingId={}", userId, money, blessingId);
        }
        Map map = new HashMap();
        String title = "祈福送大奖活动";
        String orderId = EmojiFilter.generatorOrderId();//生成订单id
        String nonceStr = WeChatUtil.getRandomStringByLength(32);//生成微信随机字符串
        try {
            OrderInfo order = new OrderInfo();
            order.setAppid(weChatConfig.getAppIdx());
            order.setMch_id(weChatConfig.getMch_id);
            order.setNonce_str(nonceStr);
            order.setBody(title);
            order.setOut_trade_no(orderId);
            int sum=Integer.parseInt(money);
            order.setTotal_fee(sum);     // 以分为单位:1元=100分
            order.setSpbill_create_ip(IpUtil.getRemoteIp(request));//获取客户端的ip地址
            order.setNotify_url(weChatConfig.getNotifyUrl());
            order.setTrade_type(trade_type);
            User user = userServiceImpl.getUserById(userId);
            if (user == null) {
                throw new ServiceException(1000, "支付用户数据库中为空，没有登录过");
            }
            user.setAvatarUrl(avatarUrl);
            user.setName(userName);
            //保存用户昵称，头像
            user.updateById();
            order.setOpenid(user.getOpenid());
            order.setSign_type("MD5");
            //生成签名
            String sign = Signature.getSign(order);
            order.setSign(sign);
            System.out.println("微信支付前:" + new Gson().toJson(order));
            LOG.info("微信支付发送前 payment order={}", new Gson().toJson(order));
            String result = HttpRequest.sendPost(url, order);
            System.out.println("微信支付同步返回:" + result);
            LOG.info("微信支付同步返回 payment result={}", new Gson().toJson(result));
            XStream xStream = new XStream();
            xStream.alias("xml", OrderReturnInfo.class);
            OrderReturnInfo returnInfo = (OrderReturnInfo) xStream.fromXML(result);
            // 二次签名
            if ("SUCCESS".equals(returnInfo.getReturn_code()) && returnInfo.getReturn_code().equals(
                    returnInfo.getResult_code())) {
                SignInfo signInfo = new SignInfo();
                signInfo.setAppId(weChatConfig.getAppIdx());
                long time = System.currentTimeMillis() / 1000;
                signInfo.setTimeStamp(String.valueOf(time));
                signInfo.setNonceStr(WeChatUtil.getRandomStringByLength(32));
                signInfo.setRepay_id("prepay_id=" + returnInfo.getPrepay_id());
                signInfo.setSignType("MD5");
                //生成签名
                String sign1 = Signature.getSign(signInfo);
                Map payInfo = new HashMap();
                payInfo.put("timeStamp", signInfo.getTimeStamp());
                payInfo.put("nonceStr", signInfo.getNonceStr());
                payInfo.put("package", signInfo.getRepay_id());
                payInfo.put("signType", signInfo.getSignType());
                payInfo.put("paySign", sign1);
                map.put("status", 200);
                map.put("msg", "下单成功!");
                map.put("data", payInfo);

                // 保存订单
                Orders orders = new Orders(orderId, nonceStr, Integer.valueOf(blessingId),
                        Constant.orderBean.STATUS_ORDER_INTEND, Integer.valueOf(userId),
                        sum, LocalDateTime.now(), 1);
                try {
                    orders.insert();
                } catch (Exception e) {
                    LOG.error("保存订单失败 orderInfo={}", new Gson().toJson(order), e);
                }
                LOG.info("保存订单成功");
                // 业务逻辑结束
                return map;
            }
            map.put("status", 500);
            map.put("msg", "下单失败!");
            map.put("data", null);
            return map;
        } catch (Exception e) {
            LOG.error("微信预支付返回出错！userId={},money={}", userId, money);
        }
        return null;
    }

    /**
     * 微信小程序支付成功回调函数
     *
     * @param request
     * @param response
     * @throws Exception
     */
    public void wxNotify(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        BufferedReader br = new BufferedReader(
                new InputStreamReader((ServletInputStream) request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        //sb为微信返回的xml
        String notityXml = sb.toString();
        String resXml = "";
        System.out.println("接收到的报文：" + notityXml);
        LOG.info("接收的报文：notityXml={}", new Gson().toJson(notityXml));
        Map map = PayUtil.doXMLParse(notityXml);

        String returnCode = (String) map.get("return_code");
        if ("SUCCESS".equals(returnCode)) {
            //验证签名是否正确
            Map<String, String> validParams = PayUtil.paraFilter(map);  //回调验签时需要去除sign和空值参数
            String validStr = PayUtil.createLinkString(
                    validParams);//把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            String sign = PayUtil.sign(validStr, WeChatConfig.getMch_key,
                    "utf-8").toUpperCase();//拼装生成服务器端验证的签名
            // 因为微信回调会有八次之多,所以当第一次回调成功了,那么我们就不再执行逻辑了
            SetParams sp = new SetParams();
            sp.nx().ex((int) DateUtils.addHours(new Date(), 1).getTime());
            var flag = jedisUtil.set(MD5.md5(sign), returnCode, sp);
            if (!flag) {
                LOG.info("已经回调过了！");
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                BufferedOutputStream out = new BufferedOutputStream(
                        response.getOutputStream());
                out.write(resXml.getBytes());
                out.flush();
                out.close();
            }
            //根据微信官网的介绍，此处不仅对回调的参数进行验签，还需要对返回的金额与系统订单的金额进行比对等
            if (sign.equals(map.get("sign"))) {
                // 根据订单查询对应自己的订单
                ordersServiceImpl.updateOrder(map.get("out_trade_no").toString(),
                        map.get("transaction_id").toString(), Constant.orderBean.STATUS_ORDER_UNBAN, map.get("openid").toString());
                //通知微信服务器已经支付成功
                resXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml> ";
            } else {
                System.out.println("微信支付回调失败!签名不一致");
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        System.out.println(resXml);
        System.out.println("微信支付回调数据结束");

        BufferedOutputStream out = new BufferedOutputStream(
                response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }

}
